﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PC.AzureMultiApp.Core.Models;
using Ionic.Zip;
using System.IO;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.Web.Administration;
using PC.AzureMultiApp.Storage;
using System.Threading;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.ServiceModel;
using System.Diagnostics;
using PC.AzureMultiApp.Core.Helpers;

namespace PC.AzureMultiApp.Core
{
    public static class DeploymentManager
    {
        public static void Deploy()
        {
            Trace.WriteLine("Deploy All Applications", "Information");

            try
            {
                ApplicationDataSource dataSource = new ApplicationDataSource();
                foreach (AzureApplicationEntity app in dataSource.GetAll())
                {
                    Deploy(Conversions.GetApplicationModel(app), false);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, "Error");
            }
        }

        public static void Deploy(ApplicationModel app, bool partialUpdate)
        {
            if (app != null)
            {
                ApplicationDataSource dataSource = null;
                try
                {

                    Trace.WriteLine("Deploy Application" + app.Name, "Information");

                    dataSource = new ApplicationDataSource();

                    string zipFile = FileHelper.GetFilesFromStorage(app.BlobUrl);

                    if (!String.IsNullOrEmpty(zipFile) && File.Exists(zipFile))
                    {
                        if (CreateApplication(app, zipFile, !partialUpdate))
                            dataSource.UpdateStatus(app.UniqueId, GlobalDef.Running);
                        else
                            dataSource.UpdateStatus(app.UniqueId, GlobalDef.Error);
                    }
                    else
                        dataSource.UpdateStatus(app.UniqueId, GlobalDef.Error);

                    File.Delete(zipFile);

                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex.Message, "Error");
                    if (dataSource != null)
                        dataSource.UpdateStatus(app.UniqueId, GlobalDef.Error);
                }
            }
        }

        public static void DeleteDeployment(string uniqueId, string applicationName, bool isWebDeploy)
        {
            if (!String.IsNullOrEmpty(applicationName) && !String.IsNullOrEmpty(uniqueId))
            {
                try
                {
                    DeleteApplication(uniqueId, applicationName, isWebDeploy);
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex.Message, "Error");
                }
            }
        }

        public static void Notify(ApplicationModel app, bool partialUpdate)
        {
            try
            {
                foreach (RoleInstance roleInstance in RoleEnvironment.Roles["WebRoleMultiApp"].Instances)
                {
                    var endPoints = roleInstance.InstanceEndpoints.Where(ip => ip.Key == "NotityEndpoint");

                    string address = String.Format("http://{0}/DeploymentService", endPoints.First().Value.IPEndpoint);

                    BasicHttpBinding binding = new BasicHttpBinding();
                    binding.CloseTimeout = TimeSpan.MaxValue;
                    binding.ReceiveTimeout = TimeSpan.MaxValue;
                    binding.SendTimeout = TimeSpan.MaxValue;
                    EndpointAddress endpoint = new EndpointAddress(address);
                    DeploymentHostClient client = new DeploymentHostClient(binding, endpoint);
                    client.ExecuteDeployment(app, partialUpdate);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, "Error");
            }
        }

        private static void DeleteApplication(string uniqueId, string applicationName, bool isWebDeploy)
        {
            string applicationPath = Path.Combine(FileHelper.GetBaseDirectory(), uniqueId);

            Trace.WriteLine("Delete Application " + applicationName, "Information");

            if (Directory.Exists(applicationPath))
            {
                if (Commands.LaunchUnistallCmdIfExists(applicationPath))
                {
                    if (isWebDeploy)
                    {
                        using (ServerManager serverManager = new ServerManager())
                        {
                            Site site = serverManager.Sites.Where(s => s.Name.Equals("DeploymentSite", StringComparison.OrdinalIgnoreCase)).First();
                            string applicationPoolName = site.Applications.First().ApplicationPoolName;

                            Application applicationToDelete = site.Applications.Where(a => a.Path.Equals("/" + applicationName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                            if (applicationToDelete != null)
                            {
                                site.Applications.Remove(applicationToDelete);
                                serverManager.CommitChanges();
                            }
                        }
                    }
                }

                if (Directory.Exists(applicationPath))
                    Directory.Delete(applicationPath, true);

            }

        }

        private static bool CreateApplication(ApplicationModel app, string zipFile, bool doBackup)
        {
            bool result = false;

            string applicationPath = Path.Combine(FileHelper.GetBaseDirectory(), app.UniqueId);

            Trace.WriteLine("Create Application " + applicationPath, "Information");

            if (!Directory.Exists(applicationPath))
                Directory.CreateDirectory(applicationPath);

            if (Commands.LaunchBeforeCmdIfExists(applicationPath))
            {
                if (FileHelper.Unzip(zipFile, applicationPath, doBackup))
                {
                    if (app.IsWebDeploy)
                    {
                        // Create Virtual Application
                        using (ServerManager serverManager = new ServerManager())
                        {
                            // I assume that there is only one site.
                            Site site = serverManager.Sites.Where(s => s.Name.Equals("DeploymentSite", StringComparison.OrdinalIgnoreCase)).First();
                            string applicationPoolName = site.Applications.First().ApplicationPoolName;

                            if (!site.Applications.Where(a => a.Path.Equals("/" + app.ApplicationName, StringComparison.OrdinalIgnoreCase)).Any())
                            {
                                Trace.WriteLine("Create Application Virtual Directory", "Information");

                                Application appSite = site.Applications.Add("/" + app.ApplicationName, applicationPath);
                                appSite.ApplicationPoolName = applicationPoolName;
                                serverManager.CommitChanges();
                            }
                        }
                    }

                    Commands.LaunchAfterAndWaitCmdIfExists(applicationPath);
                    Commands.LaunchAfterAndNoWaitCmdIfExists(applicationPath);

                    result = true;
                }
            }

            return result;

        }


    }
}
